package com.yx.cloud.product.laser.tuyapublic;

import android.graphics.PointF;
import android.util.Log;
import com.aliyun.alink.business.devicecenter.utils.HexUtils;
import com.iot.common.utils.MapHandleUtils;
import com.iot.common.utils.StringUtils;
import com.iot.product.sweeper.bean.CleanAreaInfo;
import com.iot.product.sweeper.bean.Furniture;
import com.iot.product.sweeper.bean.PathPoint;
import com.yx.cloud.MyApplication;
import com.yx.cloud.utils.Lz4Util;
import com.yx.cloud.utils.PathUtils;
import com.iot.product.sweeper.bean.AreaInfo;
import com.iot.product.sweeper.bean.CleanRecord;
import com.iot.product.sweeper.bean.Map;
import com.iot.product.sweeper.bean.MapInfo;
import com.iot.product.sweeper.bean.ObjectRecognition;
import com.iot.product.sweeper.bean.Room;
import com.iot.common.utils.LogUtils;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class TuyaPublicMapDataParser {
    public static final String TAG = "TuyaPublicMapDataParser";

    public static ParseResult parseMapData(TuyaLaserMap map, TuyaLaserPath path, List<AreaInfo> areaInfos, byte[] mapData) {
        if (mapData == null || mapData.length < 24) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
  /*     String mapTempStr = bytesToHexString(mapData);
        if (map.oldMapData != null && map.oldMapData.equals(mapTempStr)) {
            //data not change ,do nothing
            LogUtils.i("map data not change");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        } else {
            map.oldMapData = mapTempStr;
            LogUtils.i("map data has change");
        }*/

        int byteStart = 0;
        int version = getValueFromData(mapData, byteStart, 1);
        byteStart += 1;
        int mapID = getValueFromData(mapData, byteStart, 2);
       /* if(map.lastMapId != mapID){
            map.lastMapId = mapID;
            map.clear();
            Log.d("mapIdtest","lastMapId != mapId");
        }else {
            Log.d("mapIdtest","lastMapId == mapId");
        }*/
        byteStart += 2;
        int type = getValueFromData(mapData, byteStart, 1);
        byteStart += 1;
        int mapWidth = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int mapHeight = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int oriX = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int oriY = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int resolution = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int chargeX = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int chargeY = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int len = getValueFromData(mapData, byteStart, 4);//lz4压缩前数据长度

        Log.d("mapLen", "mapLen is " + len);
        if (len == 0) {
            map.mapData = null;
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_NOT_MATCH);
        }
        byteStart += 4;
        int lz4len = getValueFromData(mapData, byteStart, 2);//lz4压缩后数据长度 = 0表示压缩失败
        byteStart += 2;

        float x_min_old = map.x_min;
        float y_min_old = map.y_min;

        byte[] dstBuffer;
        if (lz4len == 0) {
            if (len + byteStart > mapData.length) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            //压缩失败--无需解压9
            dstBuffer = new byte[len];
            System.arraycopy(mapData, byteStart, dstBuffer, 0, len);
            map.byteStart = byteStart + len;
        } else {
            if (lz4len + byteStart > mapData.length) {
                LogUtils.i("map data error");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            byte[] src = new byte[lz4len];
            System.arraycopy(mapData, byteStart, src, 0, src.length);
            map.byteStart = byteStart + lz4len;
            try {
                dstBuffer = Lz4Util.decompressorByte(src, len);
            } catch (Exception e) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
        }

        if (dstBuffer == null) {
            LogUtils.i("map data decompressor error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }

        if (version == 0) {
            //普通版本--无房间信息
            int pixLength = mapWidth * mapHeight / 4;
            if (mapWidth * mapHeight % 4 != 0) {
                pixLength += 1;
            }
            LogUtils.i("map data length is" + pixLength);
            if (pixLength > len) {
                LogUtils.i("map data error ,pixLength > len");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }

            map.mapData = new int[pixLength * 4];

            for (int i = 0; i < pixLength; i++) {
                byte b = dstBuffer[i];
                int p1 = (b & 0B11000000) >> 6;
                int p2 = (b & 0B00110000) >> 4;
                int p3 = (b & 0B00001100) >> 2;
                int p4 = (b & 0B00000011) >> 0;
                map.mapData[i * 4] = p1;
                map.mapData[i * 4 + 1] = p2;
                map.mapData[i * 4 + 2] = p3;
                map.mapData[i * 4 + 3] = p4;
            }
//            LogUtils.la(map.mapData,mapWidth);
            for (int i = 0; i < map.mapData.length; i++) {
                if (map.mapData[i] == 0) {
                    map.mapData[i] = MapInfo.TYPE_ORIGIN;
                } else if (map.mapData[i] == 1) {
                    map.mapData[i] = MapInfo.TYPE_WALL;
                } else if (map.mapData[i] == 2) {
                    map.mapData[i] = MapInfo.TYPE_BORDER;
                } else if (map.mapData[i] == 3) {
                    map.mapData[i] = MapInfo.TYPE_NONE;
                }
            }
            map.tempRoomData = null;
        } else if (version == 1) {
            //分区版本
            //计算地图pix长度-----分区版本
            int pixLength = mapWidth * mapHeight;
            LogUtils.i("map data length is" + pixLength);
            if (pixLength > len) {
                LogUtils.i("map data error ,pixLength > len");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            map.mapData = new int[pixLength];
            if (map.roomsId == null) {
                map.roomsId = new HashSet<>();
            } else {
                map.roomsId.clear();
            }

//            LogUtils.lb(dstBuffer,mapWidth);
            for (int i = 0; i < pixLength; i++) {
                byte b = dstBuffer[i];
                int roomID = (b & 0B11111100) >> 2;
                if (roomID >= 0 && roomID < 32) {
                    //map.mapData[i] = roomID + 1;//转换成room id 从1开始
                    map.mapData[i] = roomID;
                    map.roomsId.add(roomID);
                } else {
                    int s = b & 0B00000011;
                    if (s == 0) {
                        map.mapData[i] = MapInfo.TYPE_ORIGIN;
                    } else if (s == 1) {
                        map.mapData[i] = MapInfo.TYPE_WALL;
                    } else if (map.mapData[i] == 2) {
                        map.mapData[i] = MapInfo.TYPE_BORDER;
                    } else if (s == 3) {
                        map.mapData[i] = MapInfo.TYPE_NONE;
                    }
                }
            }

//            LogUtils.la(map.mapData,mapWidth);

            byteStart = pixLength;

            map.tempRoomData = new byte[len - pixLength];
            System.arraycopy(dstBuffer, byteStart, map.tempRoomData, 0, map.tempRoomData.length);
        } else if (version == 2) {
            //地板材质版本
            int pixLength = mapWidth * mapHeight;
            LogUtils.i("map data length is" + pixLength);
            if (pixLength > len) {
                LogUtils.i("map data error ,pixLength > len");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            map.mapData = new int[pixLength];
            if (map.roomsId == null) {
                map.roomsId = new HashSet<>();
            } else {
                map.roomsId.clear();
            }

            for (int i = 0; i < pixLength; i++) {
                byte b = dstBuffer[i];
                int roomID = (b & 0B11111000) >> 3;
                if (roomID >= 0 && roomID < 28) {
                    //map.mapData[i] = roomID + 1;//转换成room id 从1开始
                    map.mapData[i] = roomID;
                    map.roomsId.add(roomID);
                } else {
                    int s = b & 0B00000111;
                    if (s == 0) {
                        map.mapData[i] = MapInfo.TYPE_NONE;
                    } else if (s == 1) {
                        map.mapData[i] = MapInfo.TYPE_WALL;
                    } else if (map.mapData[i] == 4) {
                        map.mapData[i] = MapInfo.TYPE_BORDER;
                    } else if (s == 7) {
                        map.mapData[i] = MapInfo.TYPE_ORIGIN;
                    }
                }
            }

            byteStart = pixLength;

            map.tempRoomData = new byte[len - pixLength];
            System.arraycopy(dstBuffer, byteStart, map.tempRoomData, 0, map.tempRoomData.length);
        }

        map.mapId = mapID;
        map.width = mapWidth;
        map.height = mapHeight;
        map.resolution = resolution / 100f;
        map.x_min = oriX / 10f;
        map.y_min = oriY / 10f;

        if (chargeX != 0 && chargeY != 0) {

            Log.d(TAG, "chargeX = " + chargeX + "chargeY = " + chargeY);
            map.dockerPosX = chargeX / 10.0f;
            map.dockerPosY = chargeY / 10.0f;

            //ZW11充电座方向无
            map.dockertheta = 0;
            //ZW充电座暂未调好 设置0,0  不显示
            //map.dockerPosX = 0;
            //map.dockerPosY = 0;
            Log.d(TAG, "map.dockerPosX = " + chargeX + "map.dockerPosY = " + chargeY);
        } else {
            Log.d(TAG, "=====0 chargeX = " + chargeX + "chargeY = " + chargeY);
            map.dockerPosX = 0;
            map.dockerPosY = 0;
        }

        //多房间地图特殊处理
        if (map.roomsId != null && map.roomsId.size() > 0) {
            getRooms(map);
        } else {
            if (map.room != null) {
                map.room.clear();
            }
        }

        //地图原始坐标和分辨率变了要刷新路径和区域、禁区
        if (x_min_old != map.x_min || y_min_old != map.y_min) {
            //重新计算路径点
            transPoseAr(path, map);
            //重新刷新区域、禁区顶点坐标
            if (map.oldForbidenLineData != null) {
                parseFrobidenLineData(map, areaInfos, StringUtils.hex2byte(map.oldForbidenLineData));
            }
            if (map.oldForbidenAreaData != null) {
                parseFrobidenAreaData(map, areaInfos, StringUtils.hex2byte(map.oldForbidenAreaData));
            }
            if (map.oldAreaData != null) {
                parseCleanAreaData(map, areaInfos, StringUtils.hex2byte(map.oldAreaData));
            }
            Log.d(TAG, "map.x_min: has change,refresh path and area");
        }

        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    public static void parseRecord(CleanRecord cleanRecord, byte[] cleanRecordData) {
        Map map = cleanRecord.getMap();
        TuyaLaserMap tuyaLaserMap = new TuyaLaserMap();
        TuyaLaserPath tuyaLaserPath = new TuyaLaserPath();
        map.setMap(tuyaLaserMap);
        map.setPath(tuyaLaserPath);

        ParseResult result = parseRecordMapData((TuyaLaserMap) map.getMap(), (TuyaLaserPath) map.getPath(), cleanRecordData);
        if (result.getCode() == ParseResult.MSG_PARSE_SUCCESS) {
            //充电座位置
            map.getPower().setX(tuyaLaserMap.dockerPosX);
            map.getPower().setY(tuyaLaserMap.dockerPosY);
            map.getPower().setRotation((float) tuyaLaserMap.dockertheta);
            result = parseRecordRoomData((TuyaLaserMap) map.getMap(), map.getRoom(), tuyaLaserMap.tempRoomData);
            if (result.getCode() == ParseResult.MSG_PARSE_SUCCESS) {
                //房间信息没有时，从地图中手动解析;
                if (tuyaLaserMap.room != null && tuyaLaserMap.room.size() > 0) {
                    if (map.getRoom().size() == 0) {
                        map.getRoom().addAll(tuyaLaserMap.room);
                    } else {
                        for (int i = 0; i < map.getRoom().size(); i++) {
                            for (int j = 0; j < tuyaLaserMap.room.size(); j++) {
                                if (tuyaLaserMap.room.get(j).getId() == map.getRoom().get(i).getId()) {
                                    map.getRoom().get(i).setCenter(tuyaLaserMap.room.get(j).getCenter());
                                }
                            }
                        }
                    }
                }
            }

            result = parseRecordPathData((TuyaLaserMap) map.getMap(), (TuyaLaserPath) map.getPath(), cleanRecordData);
            if (result.getCode() == ParseResult.MSG_PARSE_SUCCESS) {
                //机器位置
                int endIndex = tuyaLaserPath.destPathPoints.size() - 1;
                float rotation = PathUtils.getRotationFromPath(tuyaLaserPath.destPathPoints);
                map.getSweeper().set(tuyaLaserPath.destPathPoints.get(endIndex).x, tuyaLaserPath.destPathPoints.get(endIndex).y, rotation);
            }

            parseRecordForbidenLineData((TuyaLaserMap) map.getMap(), map.getArea(), cleanRecordData);

            parseRecordForbidenAreaData((TuyaLaserMap) map.getMap(), map.getArea(), cleanRecordData);
        }
    }

    public static void parseMultiMap(CleanRecord cleanRecord, byte[] cleanRecordData) {
        Map map = cleanRecord.getMap();
        TuyaLaserMap tuyaLaserMap = new TuyaLaserMap();
        TuyaLaserPath tuyaLaserPath = new TuyaLaserPath();
        map.setMap(tuyaLaserMap);
        map.setPath(tuyaLaserPath);

        ParseResult result = parseRecordMapData((TuyaLaserMap) map.getMap(), (TuyaLaserPath) map.getPath(), cleanRecordData);
        if (result.getCode() == ParseResult.MSG_PARSE_SUCCESS) {
            //充电座位置
            map.getPower().setX(tuyaLaserMap.dockerPosX);
            map.getPower().setY(tuyaLaserMap.dockerPosY);
            map.getPower().setRotation((float) tuyaLaserMap.dockertheta);
            result = parseRecordRoomData((TuyaLaserMap) map.getMap(), map.getRoom(), tuyaLaserMap.tempRoomData);
            if (result.getCode() == ParseResult.MSG_PARSE_SUCCESS) {
                //房间信息没有时，从地图中手动解析;
                if (tuyaLaserMap.room != null && tuyaLaserMap.room.size() > 0) {
                    if (map.getRoom().size() == 0) {
                        map.getRoom().addAll(tuyaLaserMap.room);
                    } else {
                        for (int i = 0; i < map.getRoom().size(); i++) {
                            for (int j = 0; j < tuyaLaserMap.room.size(); j++) {
                                if (tuyaLaserMap.room.get(j).getId() == map.getRoom().get(i).getId()) {
                                    map.getRoom().get(i).setCenter(tuyaLaserMap.room.get(j).getCenter());
                                }
                            }
                        }
                    }
                }
            }

            /*result = parseRecordPathData((ZWMap)map.getMap(),(ZWPath)map.getPath(),cleanRecordData);
            if(result.getCode() == ParseResult.MSG_PARSE_SUCCESS){
                //机器位置
                int endIndex = zwPath.destPathY.size() - 1;
                map.getSweeper().set(zwPath.destPathX.get(endIndex), zwPath.destPathY.get(endIndex));
            }*/

            parseRecordForbidenLineData((TuyaLaserMap) map.getMap(), map.getArea(), cleanRecordData);

            parseRecordForbidenAreaData((TuyaLaserMap) map.getMap(), map.getArea(), cleanRecordData);
        }
    }

    public static ParseResult parseRecordMapData(TuyaLaserMap map, TuyaLaserPath path, byte[] mapData) {
        if (mapData == null || mapData.length < 24) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        String mapTempStr = StringUtils.bytesToHexString(mapData);
        if (map.oldMapData != null && map.oldMapData.equals(mapTempStr)) {
            //data not change ,do nothing
            LogUtils.i("map data not change");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        } else {
            map.oldMapData = mapTempStr;
            LogUtils.i("map data has change");
        }
        Log.d("mapLen", "mapData is " + mapTempStr);

        int byteStart = 0;
        int version = getValueFromData(mapData, byteStart, 1);
        byteStart += 1;
        int mapID = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int type = getValueFromData(mapData, byteStart, 1);
        byteStart += 1;
        int mapWidth = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int mapHeight = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int oriX = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int oriY = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int resolution = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int chargeX = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int chargeY = getValueFromData(mapData, byteStart, 2);
        byteStart += 2;
        int len = getValueFromData(mapData, byteStart, 4);//lz4压缩前数据长度
        byteStart += 4;
        int lz4len = getValueFromData(mapData, byteStart, 2);//lz4压缩后数据长度 = 0表示压缩失败
        byteStart += 2;

        float x_min_old = map.x_min;
        float y_min_old = map.y_min;

        Log.d("mapLen", "mapLen is " + len);
        byte[] dstBuffer;
        if (lz4len == 0) {
            if (len + byteStart > mapData.length) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            dstBuffer = new byte[len];
            //压缩失败--无需解压
            System.arraycopy(mapData, byteStart, dstBuffer, 0, len);
            map.byteStart = byteStart + len;
        } else {
            if (lz4len + byteStart > mapData.length) {
                LogUtils.i("map data error");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            byte[] src = new byte[lz4len];
            System.arraycopy(mapData, byteStart, src, 0, src.length);
            map.byteStart = byteStart + lz4len;
            try {
                dstBuffer = Lz4Util.decompressorByte(src, len);
            } catch (Exception e) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }

        }

        if (dstBuffer == null) {
            LogUtils.i("map data decompressor error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }

        if (version == 0) {
            //普通版本--无房间信息
            int pixLength = mapWidth * mapHeight / 4;
            if (mapWidth * mapHeight % 4 != 0) {
                pixLength += 1;
            }
            LogUtils.i("map data length is" + pixLength);
            if (pixLength > len) {
                LogUtils.i("map data error ,pixLength > len");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }

            map.mapData = new int[pixLength * 4];

            for (int i = 0; i < pixLength; i++) {
                byte b = dstBuffer[i];
                int p1 = (b & 0B11000000) >> 6;
                int p2 = (b & 0B00110000) >> 4;
                int p3 = (b & 0B00001100) >> 2;
                int p4 = (b & 0B00000011) >> 0;
                map.mapData[i * 4] = p1;
                map.mapData[i * 4 + 1] = p2;
                map.mapData[i * 4 + 2] = p3;
                map.mapData[i * 4 + 3] = p4;
            }

            for (int i = 0; i < map.mapData.length; i++) {
                if (map.mapData[i] == 0) {
                    map.mapData[i] = MapInfo.TYPE_ORIGIN;
                } else if (map.mapData[i] == 1) {
                    map.mapData[i] = MapInfo.TYPE_WALL;
                } else if (map.mapData[i] == 3) {
                    map.mapData[i] = MapInfo.TYPE_NONE;
                }
            }

        } else if (version == 1) {
            //分区版本
            //计算地图pix长度-----分区版本
            int pixLength = mapWidth * mapHeight;
            LogUtils.i("map data length is" + pixLength);
            if (pixLength > len) {
                LogUtils.i("map data error ,pixLength > len");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            map.mapData = new int[pixLength];
            if (map.roomsId == null) {
                map.roomsId = new HashSet<>();
            } else {
                map.roomsId.clear();
            }

            for (int i = 0; i < pixLength; i++) {
                byte b = dstBuffer[i];
                int roomID = (b & 0B11111100) >> 2;
                if (roomID >= 0 && roomID < 32) {
                    //map.mapData[i] = roomID + 1;//转换成room id 从1开始
                    map.mapData[i] = roomID;
                    map.roomsId.add(roomID);
                } else {
                    int s = b & 0B00000011;
                    if (s == 0) {
                        map.mapData[i] = MapInfo.TYPE_ORIGIN;
                    } else if (s == 1) {
                        map.mapData[i] = MapInfo.TYPE_WALL;
                    } else if (s == 3) {
                        map.mapData[i] = MapInfo.TYPE_NONE;
                    }
                }
            }

            byteStart = pixLength;

            map.tempRoomData = new byte[len - pixLength];
            System.arraycopy(dstBuffer, byteStart, map.tempRoomData, 0, map.tempRoomData.length);
        } else if (version == 2) {
            //地板材质版本
            int pixLength = mapWidth * mapHeight;
            LogUtils.i("map data length is" + pixLength);
            if (pixLength > len) {
                LogUtils.i("map data error ,pixLength > len");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            map.mapData = new int[pixLength];
            if (map.roomsId == null) {
                map.roomsId = new HashSet<>();
            } else {
                map.roomsId.clear();
            }

            for (int i = 0; i < pixLength; i++) {
                byte b = dstBuffer[i];
                int roomID = (b & 0B11111000) >> 3;
                if (roomID >= 0 && roomID < 28) {
                    //map.mapData[i] = roomID + 1;//转换成room id 从1开始
                    map.mapData[i] = roomID;
                    map.roomsId.add(roomID);
                } else {
                    int s = b & 0B00000111;
                    if (s == 0) {
                        //map.mapData[i] = MapInfo.TYPE_ORIGIN;
                        map.mapData[i] = MapInfo.TYPE_NONE;
                    } else if (s == 1) {
                        map.mapData[i] = MapInfo.TYPE_WALL;
                    } else if (s == 7) {
                        //map.mapData[i] = MapInfo.TYPE_NONE;
                        map.mapData[i] = MapInfo.TYPE_ORIGIN;
                    }
                }
            }

            byteStart = pixLength;

            map.tempRoomData = new byte[len - pixLength];
            System.arraycopy(dstBuffer, byteStart, map.tempRoomData, 0, map.tempRoomData.length);
        }

        map.mapId = mapID;
        map.width = mapWidth;
        map.height = mapHeight;
        map.resolution = resolution / 100f;
        map.x_min = oriX / 10f;
        map.y_min = oriY / 10f;

        if (chargeX != 0 && chargeY != 0) {
            map.dockerPosX = chargeX / 10f;
            map.dockerPosY = chargeY / 10f;
            map.dockertheta = 0;
        } else {
            map.dockerPosX = 0;
            map.dockerPosY = 0;
        }

        //多房间地图特殊处理
        if (map.roomsId != null && map.roomsId.size() > 0) {
            getRooms(map);
        } else {
            if (map.room != null) {
                map.room.clear();
            }
        }

        //地图原始坐标和分辨率变了要刷新路径和区域、禁区
        if (x_min_old != map.x_min || y_min_old != map.y_min) {
            //重新计算路径点
            transPoseAr(path, map);
            //重新刷新区域、禁区顶点坐标
            map.oldAreaData = "";
            Log.d(TAG, "map.x_min: has change,refresh path and area");
        }

        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    /**
     * 解析路径数据
     * 轨迹数据， 分为增量数据和全量数据
     * 地图坐标数据为一维数组，格式：{x1,y1,x2,y2,x3,y3......}
     * 增量数据通过poseFrom poseTo来标记位置，
     */
    public static ParseResult<PathParseResult> parseRecordPathData(TuyaLaserMap map, TuyaLaserPath path, byte[] pathData) {
        int byteStart = map.byteStart;
        if (pathData.length < byteStart + 13) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        String pathTempStr = StringUtils.bytesToHexString(pathData);
        if (path.oldPathData != null && path.oldPathData.equals(pathTempStr)) {
            //data not change ,do nothing
            LogUtils.i("path data not change");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        } else {
            path.oldPathData = pathTempStr;
            LogUtils.i("path data has change");
        }

        int version = getValueFromData(pathData, byteStart, 1);
        byteStart += 1;
        int pathID = getValueFromData(pathData, byteStart, 2);
        byteStart += 2;
        int initFlag = getValueFromData(pathData, byteStart, 1);
        byteStart += 1;
        int type = getValueFromData(pathData, byteStart, 1);
        byteStart += 1;
        int count = getValueFromData(pathData, byteStart, 4);
        byteStart += 4;
        int direction = getValueFromData(pathData, byteStart, 2);
        byteStart += 2;
        int lz4len = getValueFromData(pathData, byteStart, 2);//lz4压缩后数据长度 =0表示压缩失败
        byteStart += 2;

        int len = count * 4;
        if (len < 0) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }

        byte[] dstBuffer = null;
        if (lz4len == 0) {
            if (len + byteStart > pathData.length) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            dstBuffer = new byte[len];
            //压缩失败--无需解压
            System.arraycopy(pathData, byteStart, dstBuffer, 0, len);
            byteStart += len;
        } else if (lz4len > 0) {
            if (lz4len + byteStart > pathData.length) {
                LogUtils.i("path data error");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }

            byte[] src = new byte[lz4len];
            System.arraycopy(pathData, byteStart, src, 0, src.length);

            byteStart += lz4len;
            try {
                dstBuffer = Lz4Util.decompressorByte(src, len);
            } catch (Exception e) {
                LogUtils.i("dsafasfasf");
                Lz4Util.createFile(pathData, MyApplication.get().getFilesDir().getAbsolutePath() + "/" + "aaaaaaaa.txt");
                LogUtils.i("dsafasfasf1");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
        }
        map.byteStart = byteStart;

        if (dstBuffer == null) {
            LogUtils.i("map data decompressor error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }

        path.pathID = pathID;
        map.pathId = pathID;

        path.pathPoints.clear();

        //读路径点
        for (int i = 0; i < count; i++) {
            int start = i * 4;
            byte b1 = dstBuffer[start];
            byte b2 = dstBuffer[start + 1];
            byte b3 = dstBuffer[start + 2];
            byte b4 = dstBuffer[start + 3];
            float x = StringUtils.convertTwoBytesToInt(b1, b2);
            float y = StringUtils.convertTwoBytesToInt(b3, b4);
            int pointType = (b2 & 1) * 2 + (b4 & 1); //取路径点x y 最后一位 拼成2位  00清扫 01转场 10回冲 11拖地
//            LogUtils.i("path point type2: "+x +" , "+y+ " : "+pointType);

            path.pathPoints.add(new PathPoint(x, y, pointType));
        }

        if (path.pathPoints.size() > 0) {
            transPoseAr(path, map);
            //继续获取
            Log.d("ldPath", "path data ===== " + "refresh path count is " + count);

        } else {
            path.clear();
            return new ParseResult<>(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }

        return new ParseResult<>(ParseResult.MSG_PARSE_SUCCESS);
    }

    /**
     * 解析清扫记录虚拟墙数据
     *
     * @param map
     * @param areaInfos
     * @param forbidenLineData
     * @return
     */
    public static ParseResult parseRecordForbidenLineData(TuyaLaserMap map, List<AreaInfo> areaInfos, byte[] forbidenLineData) {
        int byteStart = map.byteStart;
        if (forbidenLineData.length > byteStart) {
            //略过帧头和协议版本
            byteStart += 2;
            if (forbidenLineData.length < byteStart + 1) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            int dataLen = getValueFromData(forbidenLineData, byteStart, 1);
            byteStart += 1;

            byte[] data = null;
            if (dataLen + byteStart > forbidenLineData.length) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            if (dataLen > 0) {
                data = new byte[dataLen];
                System.arraycopy(forbidenLineData, byteStart, data, 0, data.length);
                byteStart += (dataLen + 1);
                map.byteStart = byteStart;
            }

            byte[] lineData = new byte[data.length - 1];
            System.arraycopy(data, 1, lineData, 0, lineData.length);

            if (lineData.length < 1) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            int count = getValueFromData(lineData, 0, 1);
            Log.d("liunian", "forbidenLineData count " + count);
            if (lineData.length - 1 == count * 8) {
                clearForbidenLines(areaInfos);
                for (int i = 0; i < count; i++) {
                    int start = 1 + i * 8;
                    byte[] dst = new byte[8];
                    System.arraycopy(lineData, start, dst, 0, dst.length);
                    CleanAreaInfo areaInfo = new CleanAreaInfo();
                    areaInfo.setBorder(getPoints(dst, map));
                    areaInfo.setType(AreaInfo.TYPE_FORBIDDEN_LINE);
                    areaInfo.setId(400 + i);
                    areaInfos.add(areaInfo);
                }
            } else {
                LogUtils.i("forbidenLineData data error");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }

        }
        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }


    /**
     * 解析清扫记录虚拟墙数据
     *
     * @param map
     * @param areaInfos
     * @param forbidenLineData
     * @return
     */
    public static ParseResult parseRecordForbidenAreaData(TuyaLaserMap map, List<AreaInfo> areaInfos, byte[] forbidenLineData) {
        int byteStart = map.byteStart;
        if (forbidenLineData.length > byteStart) {
            //略过帧头和协议版本
            byteStart += 2;
            if (forbidenLineData.length < byteStart + 1) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            int dataLen = getValueFromData(forbidenLineData, byteStart, 1);
            byteStart += 1;

            byte[] data = null;
            if (dataLen + byteStart > forbidenLineData.length) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            if (dataLen > 0) {
                data = new byte[dataLen];
                System.arraycopy(forbidenLineData, byteStart, data, 0, data.length);
                byteStart += (dataLen + 1);
                map.byteStart = byteStart;
            }

            byte[] lineData = new byte[data.length - 1];
            System.arraycopy(data, 1, lineData, 0, lineData.length);

            if (lineData.length < 1) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }

            int count = getValueFromData(lineData, 0, 1);
            Log.d("liunian", "forbidenAreaData count " + count);
            if (lineData.length - 1 == count * 18) {
                clearForbidenArea(areaInfos);
                for (int i = 0; i < count; i++) {
                    int start = 1 + i * 18;
                    byte[] dst = new byte[18];
                    System.arraycopy(lineData, start, dst, 0, dst.length);
                    CleanAreaInfo areaInfo = new CleanAreaInfo();
                    if (dst[0] == 0x00) {
                        areaInfo.setType(AreaInfo.TYPE_FORBIDDEN);
                    } else if (dst[0] == 0x02) {
                        areaInfo.setType(AreaInfo.TYPE_FORBIDDEN_MOP);
                    }
                    byte[] dst1 = new byte[16];
                    System.arraycopy(dst, 2, dst1, 0, dst1.length);
                    areaInfo.setBorder(getPoints(dst1, map));
                    areaInfo.setId(300 + i);
                    areaInfos.add(areaInfo);
                }
            } else {
                LogUtils.i("forbidenLineData data error");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
        }
        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    /**
     * 解析房间数据
     *
     * @param map
     * @param roomInfos
     * @param roomsData
     * @return
     */
    public static ParseResult parseRecordRoomData(TuyaLaserMap map, List<Room> roomInfos, byte[] roomsData) {

        if (roomsData == null || roomsData.length < 2) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        String roomsTempStr = HexUtils.bytesToHexString(roomsData);
        if (map.oldRoomData != null && map.oldRoomData.equals(roomsTempStr)) {
            LogUtils.i("rooms data not change");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        } else {
            map.oldRoomData = roomsTempStr;
            LogUtils.i("rooms data has change");
        }

        int byteStart = 0;
        int region_id = getValueFromData(roomsData, byteStart, 1);
        byteStart += 1;
        int region_num = getValueFromData(roomsData, byteStart, 1);
        if (region_num <= 0) {
            roomInfos.clear();
            return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
        }

        roomInfos.clear();

        byteStart += 1;

        if (roomsData.length < byteStart + region_num * (26 + 20 + 1)) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }

        for (int i = 0; i < region_num; i++) {
            Room roomInfo = new Room();
            byte[] roomProperties = new byte[26];
            System.arraycopy(roomsData, byteStart, roomProperties, 0, 26);

            int pStart = 0;
            //int roomID = getValueFromData(roomProperties, pStart, 2) + 1;//房间id从1开始,暂时这样处理
            int roomID = getValueFromData(roomProperties, pStart, 2);
            Log.d("zw", "room roomID is " + roomID);
            pStart += 2;
            int cleanOrder = getValueFromData(roomProperties, pStart, 2);
            pStart += 2;
            int cleanTime = getValueFromData(roomProperties, pStart, 2);
            Log.d("zw", "room cleanTime is " + cleanTime);
            pStart += 2;
            int mopTime = getValueFromData(roomProperties, pStart, 2);
            pStart += 2;
            int colorId = getValueFromData(roomProperties, pStart, 1);
            Log.d("zw", "room colorId is " + colorId);
            pStart += 1;
            int unClean = getValueFromData(roomProperties, pStart, 1);
            pStart += 1;
            int unMop = getValueFromData(roomProperties, pStart, 1);
            pStart += 1;
            int funLavel = getValueFromData(roomProperties, pStart, 1);
            Log.d("zw", "room funLavel is " + funLavel);
            pStart += 1;
            int waterLavel = getValueFromData(roomProperties, pStart, 1);
            pStart += 1;
            Log.d("zw", "room waterLavel is " + waterLavel);
            int yMop = getValueFromData(roomProperties, pStart, 1);
            pStart += 1;

            byteStart += 26;

            //房间名称
            byte[] roomName = new byte[20];
            System.arraycopy(roomsData, byteStart, roomName, 0, 20);
            int roomNameLen = getValueFromData(roomName, 0, 1);
            Log.d("zw", "roomNameLen" + roomNameLen);
            if (roomNameLen > 0 && roomNameLen <= 19) {
                byte[] namebytes = new byte[roomNameLen];
                System.arraycopy(roomName, 1, namebytes, 0, roomNameLen);
                String name = null;
                try {
                    name = new String(namebytes, "utf-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                roomInfo.setName(name);
                Log.d("zw", "room name is " + name);
            } else {
                roomInfo.setName("Room" + (roomID + 1));
            }
            byteStart += 20;

            //多边形顶点个数--未使用
            int vertices_num = getValueFromData(roomsData, byteStart, 1);
            byteStart += 1;

            //区域顶点坐标--未使用
            int vertices_data_num = vertices_num * 2 * 2;
            byte[] vertices_data = new byte[vertices_data_num];
            System.arraycopy(roomsData, byteStart, vertices_data, 0, vertices_data_num);
            byteStart += vertices_data_num;

            roomInfo.setId(roomID);
            roomInfo.setOrder(cleanOrder);
            roomInfo.setCleanTimes(cleanTime);
            roomInfo.setSuction(funLavel);
            roomInfo.setHumidity(waterLavel);
            roomInfo.setCenter(new PointF(0, 0));
            roomInfos.add(roomInfo);
        }

        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    public static List<Room> getRooms(TuyaLaserMap map) {
        if (map.room == null) {
            map.room = new ArrayList<>();
        } else {
            map.room.clear();
        }
        for (Integer roomId : map.roomsId) {
            int value = roomId.intValue();
            LFRoomInfo room = new LFRoomInfo();
            room.setId(value);
            room.setTag(value + "");
            room.setName("Room" + value);
            room.setOrder(0);
            PointF roomCenterPoint = MapHandleUtils.getRoomCenter(roomId, map.mapData, map.width, map.height);
            if (roomCenterPoint != null) {
                room.setCenter(roomCenterPoint);
            } else {
                room.setCenter(new PointF(0, 0));
            }
            map.room.add(room);
            Log.d(TAG, "map.room value " + value);
        }
        if (map.room != null) {
            Log.d(TAG, "roomTagStr === " + map.room + "  room size is " + map.room.size());
        }
        return map.room;
    }

    public static int getValueFromData(byte[] data, int start, int length) {
        byte[] bytes = new byte[length];
        int result = 0;
        for (int i = 0; i < length; i++) {
            bytes[i] = data[i + start];
            int p = 8 * (length - i - 1);
            result += (bytes[i] & 0xff) << p;
        }

        return result;
    }

    public static List<byte[]> getCmdAndData(byte[] packageData) {
        List<byte[]> dataList = new ArrayList<>();
        int start = 0;
        int dataLen = 0;
        while (packageData.length > start) {
            int packageHead = packageData[start] & 0xff;
            if (packageHead == 0xaa) {
                start += 2;
                dataLen = getValueFromData(packageData, start, 1);
                Log.d("x333", "0xaa cmd len is " + dataLen);
                start += 1;
            } else if (packageHead == 0xab) {
                start += 2;
                dataLen = getValueFromData(packageData, start, 4);
                Log.d("x333", "0xab cmd len is " + dataLen);
                start += 4;
            } else {
                return dataList;
            }

            byte[] data;
            if (dataLen + start > packageData.length) {
                return dataList;
            }
            if (dataLen > 0) {
                data = new byte[dataLen];
                System.arraycopy(packageData, start, data, 0, data.length);
                dataList.add(data);
            }
            start += (dataLen + 1);
        }

        return dataList;
    }

    public static byte[] getCmdAndData1(byte[] packageData) {
        //{"35":"ab0000000007350400000001144e"}
        //{"35":"ab0000000007350400000001144e"}
        //{"35":"ab00000000073504000000013c76"}
        //{"35":"ab00000000073504000000000039"}
        //{"35":"ab00000000073504000000013c76"}
        //{"35":"ab0000000007350400000002649f"}
        //{"35":"ab000000000735040000000364a0"}
        byte[] bytes = null;
        int start = 0;
        int dataLen;
        start += 2;
        dataLen = getValueFromData(packageData, start, 4);
        start += 4;
        if (dataLen + start > packageData.length) {
            return bytes;
        }
        if (dataLen > 0) {
            bytes = new byte[dataLen];
            System.arraycopy(packageData, start, bytes, 0, bytes.length);
        }

        return bytes;
    }


    /**
     * 解析路径数据
     * 轨迹数据， 分为增量数据和全量数据
     * 地图坐标数据为一维数组，格式：{x1,y1,x2,y2,x3,y3......}
     * 增量数据通过poseFrom poseTo来标记位置，
     */
    public static ParseResult<PathParseResult> parsePathData(TuyaLaserMap map, TuyaLaserPath path, byte[] pathData) {
        if (pathData.length < 13) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
   /*     String pathTempStr = bytesToHexString(pathData);
        if (path.oldPathData != null && path.oldPathData.equals(pathTempStr)) {
            //data not change ,do nothing
            LogUtils.i("path data not change");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        } else {
            path.oldPathData = pathTempStr;
            LogUtils.i("path data has change");
        }*/

        int byteStart = 0;
        int version = getValueFromData(pathData, byteStart, 1);
        byteStart += 1;
        int pathID = getValueFromData(pathData, byteStart, 2);
        byteStart += 2;
        int initFlag = getValueFromData(pathData, byteStart, 1);
        byteStart += 1;
        int type = getValueFromData(pathData, byteStart, 1);
        byteStart += 1;
        int count = getValueFromData(pathData, byteStart, 4);
        Log.d("path refresh", "path points is " + count);
        if (count < 0) {
            LogUtils.i("path data error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        byteStart += 4;
        int direction = getValueFromData(pathData, byteStart, 2);
        byteStart += 2;
        int lz4len = getValueFromData(pathData, byteStart, 2);//lz4压缩后数据长度 =0表示压缩失败
        byteStart += 2;

        int len = count * 4;
        if (len < 0) {
            LogUtils.i("path data error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        byte[] dstBuffer = null;
        if (lz4len == 0) {
            if (len + byteStart > pathData.length) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            dstBuffer = new byte[len];
            //LogUtils.i("map data zip error"); //压缩失败--无需解压
            System.arraycopy(pathData, byteStart, dstBuffer, 0, len);
            byteStart += len;
        } else if (lz4len > 0) {
            if (lz4len + byteStart > pathData.length) {
                LogUtils.i("path data error");
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
            byte[] src = new byte[lz4len];
            for (int i = 0; i < lz4len; i++) {
                src[i] = pathData[byteStart + i];
            }
            byteStart += lz4len;
            try {
                dstBuffer = Lz4Util.decompressorByte(src, len);
            } catch (Exception e) {
                return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
            }
        }

        if (dstBuffer == null) {
            LogUtils.i("map data decompressor error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }

        path.pathID = pathID;
        map.pathId = pathID;

        path.pathPoints.clear();

        //读路径点
        for (int i = 0; i < count; i++) {
            int start = i * 4;
            byte b1 = dstBuffer[start];
            byte b2 = dstBuffer[start + 1];
            byte b3 = dstBuffer[start + 2];
            byte b4 = dstBuffer[start + 3];
            float x = StringUtils.convertTwoBytesToInt(b1, b2);
            float y = StringUtils.convertTwoBytesToInt(b3, b4);
            int pointType = (b2 & 0B00000001) * 2 + (b4 & 0B00000001); //取路径点x y 最后一位 拼成2位  00清扫 01转场 10回冲 11拖地
            path.pathPoints.add(new PathPoint(x, y, pointType));
        }

        if (path.pathPoints.size() > 0) {
            transPoseAr(path, map);
            //继续获取
            Log.d("ldPath", "path data ===== " + "refresh path count is " + count);

        } else {
            path.clear();
            return new ParseResult<>(ParseResult.MSG_PARSE_CLEAR_DATA);
        }

        return new ParseResult<>(ParseResult.MSG_PARSE_SUCCESS);
    }

    /**
     * 解析房间数据
     *
     * @param map
     * @param roomInfos
     * @param roomsData
     * @return
     */
    public static ParseResult parseRoomData(TuyaLaserMap map, List<Room> roomInfos, byte[] roomsData) {

        if (roomsData.length < 2) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        /*String roomsTempStr = bytesToHexString(roomsData);
        if (map.oldRoomData != null && map.oldRoomData.equals(roomsTempStr)) {
            //data not change ,do nothing
            LogUtils.i("rooms data not change");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        } else {
            map.oldRoomData = roomsTempStr;
            LogUtils.i("rooms data has change");
        }*/

        int byteStart = 0;
        int region_id = getValueFromData(roomsData, byteStart, 1);
        byteStart += 1;
        int region_num = getValueFromData(roomsData, byteStart, 1);
        if (region_num <= 0) {
            roomInfos.clear();
            return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
        }

        roomInfos.clear();

        byteStart += 1;
        if (roomsData.length < byteStart + region_num * (26 + 20 + 1)) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        for (int i = 0; i < region_num; i++) {
            Room roomInfo = new Room();
            byte[] roomProperties = new byte[26];
            System.arraycopy(roomsData, byteStart, roomProperties, 0, 26);

            int pStart = 0;
            //int roomID = getValueFromData(roomProperties, pStart, 2) + 1;//房间id从1开始,暂时这样处理
            int roomID = getValueFromData(roomProperties, pStart, 2);
            Log.d("zw", "room roomID is " + roomID);
            pStart += 2;
            int cleanOrder = getValueFromData(roomProperties, pStart, 2);
            Log.d("zw", "room " + roomID + " cleanOrder is " + cleanOrder);
            if (cleanOrder == 65535) {
                cleanOrder = 0;
            }
            pStart += 2;
            int cleanTime = getValueFromData(roomProperties, pStart, 2);
            Log.d("zw", "room cleanTime is " + cleanTime);
            pStart += 2;
            int mopTime = getValueFromData(roomProperties, pStart, 2);
            pStart += 2;
            int colorId = getValueFromData(roomProperties, pStart, 1);
            Log.d("zw", "room colorId is " + colorId);
            pStart += 1;
            int unClean = getValueFromData(roomProperties, pStart, 1);
            pStart += 1;
            int unMop = getValueFromData(roomProperties, pStart, 1);
            pStart += 1;
            int funLavel = getValueFromData(roomProperties, pStart, 1);
            Log.d("zw", "room funLavel is " + funLavel);
            pStart += 1;
            int waterLavel = getValueFromData(roomProperties, pStart, 1);
            pStart += 1;
            Log.d("zw", "room waterLavel is " + waterLavel);
            int yMop = getValueFromData(roomProperties, pStart, 1);
            pStart += 1;

            byteStart += 26;

            //房间名称
            byte[] roomName = new byte[20];
            System.arraycopy(roomsData, byteStart, roomName, 0, 20);
            int roomNameLen = getValueFromData(roomName, 0, 1);
            Log.d("zw", "roomNameLen" + roomNameLen);
            if (roomNameLen > 0 && roomNameLen <= 19) {
                byte[] namebytes = new byte[roomNameLen];
                System.arraycopy(roomName, 1, namebytes, 0, roomNameLen);
                String name = null;
                try {
                    name = new String(namebytes, "utf-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                roomInfo.setName(name);
                Log.d("zw", "room name is " + name);
            } else {
                roomInfo.setName("Room" + (roomID + 1));//room id 从 0 开始，房间号+1；
            }
            byteStart += 20;

            //多边形顶点个数--未使用
            int vertices_num = getValueFromData(roomsData, byteStart, 1);
            //NSLog(@"----- zw11 room info ---- vertices_num:%d",vertices_num);
            byteStart += 1;

            //区域顶点坐标--未使用
            int vertices_data_num = vertices_num * 2 * 2;
            if (vertices_data_num + byteStart <= roomsData.length) {
                byte[] vertices_data = new byte[vertices_data_num];
                System.arraycopy(roomsData, byteStart, vertices_data, 0, vertices_data_num);
                byteStart += vertices_data_num;
            }


            roomInfo.setId(roomID);
            roomInfo.setOrder(cleanOrder);
            roomInfo.setCleanTimes(cleanTime);
            roomInfo.setSuction(funLavel);
            roomInfo.setHumidity(waterLavel);
            roomInfo.setCenter(new PointF(0, 0));
            roomInfos.add(roomInfo);
        }

        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    /**
     * 解析障碍物/家具数据
     *
     * @param map
     * @param furnitureList
     * @param objectRecognitions
     * @param obstacleAndFurnitureData
     * @return
     */
    public static ParseResult parseObstacleAndFurnitureData(TuyaLaserMap map, List<Furniture> furnitureList, List<ObjectRecognition> objectRecognitions, byte[] obstacleAndFurnitureData) {
        if (obstacleAndFurnitureData == null || obstacleAndFurnitureData.length < 2) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        furnitureList.clear();
        objectRecognitions.clear();
        int count = getValueFromData(obstacleAndFurnitureData, 0, 2);
        if (obstacleAndFurnitureData.length - 2 == count * 16) {
            for (int i = 0; i < count; i++) {
                int start = 2 + i * 16;
                byte[] dst = new byte[16];
                if (obstacleAndFurnitureData == null || obstacleAndFurnitureData.length < start + dst.length) {
                    return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
                }

                System.arraycopy(obstacleAndFurnitureData, start, dst, 0, dst.length);
                int cate = getValueFromData(dst, 2, 1);
                if (cate == 0) {
                    objectRecognitions.add(parseObject(map, dst));
                    //障碍物解析
                } else if (cate == 1) {
                    //家具解析
                    furnitureList.add(parseFurniture(map, dst));
                }
            }
        } else {
            LogUtils.i("ObstacleAndFurnitureData data not error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    public static ObjectRecognition parseObject(TuyaLaserMap map, byte[] dst) {
        ObjectRecognition objectRecognition = new ObjectRecognition();
        int pStart = 0;
        int id = getValueFromData(dst, pStart, 2);
        objectRecognition.setId(id);
        Log.d("Obstacle", "id is " + id);
        pStart += 2;
        int category = getValueFromData(dst, pStart, 1);
        Log.d("Obstacle", "category is " + category);
        pStart += 1;
        int type = getValueFromData(dst, pStart, 2);
        objectRecognition.setType(type);
        Log.d("Obstacle", "type is " + type);
        pStart += 2;
        //读中心点
        byte b1 = dst[pStart];
        byte b2 = dst[pStart + 1];
        byte b3 = dst[pStart + 2];
        byte b4 = dst[pStart + 3];
        float x = StringUtils.convertTwoBytesToInt(b1, b2);
        float y = StringUtils.convertTwoBytesToInt(b3, b4);
        x = x / 10.0f;
        y = y / 10.0f;
        x = map.x_min + x;
        y = map.y_min - y;
        objectRecognition.setX(x);
        objectRecognition.setY(y);
        Log.d("Obstacle", "center point is " + "( " + x + "," + y + ")");
        pStart += 4;
        int width = getValueFromData(dst, pStart, 2);
        //objectRecognition.setWidth(width);
        pStart += 2;
        Log.d("Obstacle", "width is " + width);
        int height = getValueFromData(dst, pStart, 2);
        //objectRecognition.setHeight(height);
        pStart += 2;
        Log.d("Obstacle", "height is " + height);
        int direction = getValueFromData(dst, pStart, 2);
        objectRecognition.setRotation(direction);
        pStart += 2;
        Log.d("Obstacle", "direction is " + direction);
        int match = getValueFromData(dst, pStart, 1);
        objectRecognition.setSimilarity(match);
        pStart += 1;
        Log.d("Obstacle", "match is " + match);
        return objectRecognition;
    }

    public static Furniture parseFurniture(TuyaLaserMap map, byte[] dst) {
        Furniture furniture = new Furniture();
        int pStart = 0;
        int id = getValueFromData(dst, pStart, 2);
        furniture.setId(id);
        Log.d("Obstacle", "id is " + id);
        pStart += 2;
        int category = getValueFromData(dst, pStart, 1);
        Log.d("Obstacle", "category is " + category);
        pStart += 1;
        int type = getValueFromData(dst, pStart, 2);
        furniture.setType(type);
        Log.d("Obstacle", "type is " + type);
        pStart += 2;
        //读中心点
        byte b1 = dst[pStart];
        byte b2 = dst[pStart + 1];
        byte b3 = dst[pStart + 2];
        byte b4 = dst[pStart + 3];
        float x = StringUtils.convertTwoBytesToInt(b1, b2);
        float y = StringUtils.convertTwoBytesToInt(b3, b4);
        x = x / 10.0f;
        y = y / 10.0f;
        x = map.x_min + x;
        y = map.y_min - y;
        furniture.setX(x);
        furniture.setY(y);
        Log.d("Obstacle", "center point is " + "( " + x + "," + y + ")");
        pStart += 4;
        int width = getValueFromData(dst, pStart, 2);
        furniture.setWidth(width);
        pStart += 2;
        Log.d("Obstacle", "width is " + width);
        int height = getValueFromData(dst, pStart, 2);
        furniture.setHeight(height);
        pStart += 2;
        Log.d("Obstacle", "height is " + height);
        int direction = getValueFromData(dst, pStart, 2);
        furniture.setRotation(direction);
        pStart += 2;
        Log.d("Obstacle", "direction is " + direction);
        int match = getValueFromData(dst, pStart, 1);
        furniture.setSimilarity(match);
        pStart += 1;
        Log.d("Obstacle", "match is " + match);
        return furniture;
    }

    /**
     * 解析区域数据
     *
     * @param map
     * @param areaInfos
     * @param cleanAreaData
     * @return
     */
    public static ParseResult parseCleanAreaData(TuyaLaserMap map, List<AreaInfo> areaInfos, byte[] cleanAreaData) {
        if (cleanAreaData == null || cleanAreaData.length < 2) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        map.oldAreaData = StringUtils.byte2hex(cleanAreaData);
        int cleanTimes = getValueFromData(cleanAreaData, 0, 1);
        Log.d("nnn", "received area cleanTimes is " + cleanTimes);
        int count = getValueFromData(cleanAreaData, 1, 1);
        if (cleanAreaData.length - 2 == count * 17) {
            clearCleanArea(areaInfos);
            for (int i = 0; i < count; i++) {
                int start = 2 + i * 17;
                byte[] dst = new byte[17];
                if (cleanAreaData == null || cleanAreaData.length < start + dst.length) {
                    return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
                }
                System.arraycopy(cleanAreaData, start, dst, 0, dst.length);
                CleanAreaInfo areaInfo = new CleanAreaInfo();
                byte[] dst1 = new byte[16];
                System.arraycopy(dst, 1, dst1, 0, dst1.length);
                areaInfo.setBorder(getPoints(dst1, map));
                areaInfo.setId(200 + i);
                areaInfo.setType(AreaInfo.TYPE_CLEAN);
                areaInfo.setCleanTimes(cleanTimes);
                areaInfos.add(areaInfo);
            }
        } else {
            LogUtils.i("forbidenLineData data not error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    /**
     * 解析虚拟墙数据
     *
     * @param map
     * @param areaInfos
     * @param forbidenLineData
     * @return
     */
    public static ParseResult parseFrobidenLineData(TuyaLaserMap map, List<AreaInfo> areaInfos, byte[] forbidenLineData) {
        if (forbidenLineData == null || forbidenLineData.length < 1) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        map.oldForbidenLineData = StringUtils.byte2hex(forbidenLineData);
        int count = getValueFromData(forbidenLineData, 0, 1);
        if (forbidenLineData.length - 1 == count * 8) {
            clearForbidenLines(areaInfos);
            for (int i = 0; i < count; i++) {
                int start = 1 + i * 8;
                byte[] dst = new byte[8];
                if (forbidenLineData == null || forbidenLineData.length < start + dst.length) {
                    return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
                }
                System.arraycopy(forbidenLineData, start, dst, 0, dst.length);
                CleanAreaInfo areaInfo = new CleanAreaInfo();
                areaInfo.setBorder(getPoints(dst, map));
                areaInfo.setType(AreaInfo.TYPE_FORBIDDEN_LINE);
                areaInfo.setId(400 + i);
                areaInfos.add(areaInfo);
            }
        } else {
            LogUtils.i("forbidenLineData data error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        //aa0002130013aa00021b001b
        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    /**
     * 解析禁区数据
     *
     * @param map
     * @param areaInfos
     * @param forbidenAreaData
     * @return
     */
    public static ParseResult parseFrobidenAreaData(TuyaLaserMap map, List<AreaInfo> areaInfos, byte[] forbidenAreaData) {
        if (forbidenAreaData == null || forbidenAreaData.length < 1) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        map.oldForbidenAreaData = StringUtils.byte2hex(forbidenAreaData);
        int count = getValueFromData(forbidenAreaData, 0, 1);
        if (forbidenAreaData.length - 1 == count * 18) {
            clearForbidenArea(areaInfos);
            for (int i = 0; i < count; i++) {
                int start = 1 + i * 18;
                byte[] dst = new byte[18];
                if (forbidenAreaData == null || forbidenAreaData.length < start + dst.length) {
                    return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
                }
                System.arraycopy(forbidenAreaData, start, dst, 0, dst.length);
                CleanAreaInfo areaInfo = new CleanAreaInfo();
                if (dst[0] == 0x00) {
                    areaInfo.setType(AreaInfo.TYPE_FORBIDDEN);
                } else if (dst[0] == 0x02) {
                    areaInfo.setType(AreaInfo.TYPE_FORBIDDEN_MOP);
                }
                byte[] dst1 = new byte[16];
                System.arraycopy(dst, 2, dst1, 0, dst1.length);
                areaInfo.setBorder(getPoints(dst1, map));
                areaInfo.setId(300 + i);
                areaInfos.add(areaInfo);
            }
        } else {
            LogUtils.i("forbidenLineData data error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }


    /**
     * 解析定制模式数据
     *
     * @param rooms
     * @param customInfoData
     * @return
     */
    public static ParseResult parseCustomInfoData(List<Room> rooms, byte[] customInfoData) {
        //{"15":"aa000c230202ffffff0103ffffff0126"}
        if (customInfoData == null || customInfoData.length < 1) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        int count = getValueFromData(customInfoData, 0, 1);
        if (customInfoData.length - 1 == count * 5) {
            for (int i = 0; i < count; i++) {
                int start = 1 + i * 5;
                byte[] dst = new byte[5];
                if (customInfoData == null || customInfoData.length < start + dst.length) {
                    return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
                }
                System.arraycopy(customInfoData, start, dst, 0, dst.length);
                int roomId = getValueFromData(dst, 0, 1);
                for (Room room : rooms) {
                    if (room.getId() != roomId) {
                        continue;
                    }
                    int sunction = getValueFromData(dst, 1, 1);
                    int water = getValueFromData(dst, 2, 1);
                    int cleanTimes = getValueFromData(dst, 4, 1);
                    room.setSuction(sunction);
                    room.setHumidity(water);
                    room.setCleanTimes(cleanTimes);
                    Log.d("zw", "custom info is id " + roomId + "sunction = " + sunction + "; water = " + water + "; cleanTimes  = " + cleanTimes);
                    break;
                }
            }
        } else {
            LogUtils.i("customInfoData data error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    /**
     * 解析定制模式数据
     *
     * @param rooms
     * @param customInfoData
     * @return
     */
    public static ParseResult parseRoomNameData(List<Room> rooms, byte[] customInfoData) {
        if (customInfoData == null || customInfoData.length < 1) {
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        int count = getValueFromData(customInfoData, 0, 1);
        if (customInfoData.length - 1 == count * 21) {
            for (int i = 0; i < count; i++) {
                int start = 1 + i * 21;
                byte[] dst = new byte[21];
                if (customInfoData == null || customInfoData.length < start + dst.length) {
                    return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
                }
                System.arraycopy(customInfoData, start, dst, 0, dst.length);
                int roomId = getValueFromData(dst, 0, 1);
                for (Room room : rooms) {
                    if (room.getId() != roomId) {
                        continue;
                    }
                    int roomNameLen = getValueFromData(dst, 1, 1);
                    Log.d("zw", "roomNameLen" + roomNameLen);
                    if (roomNameLen > 0 && roomNameLen <= 19) {
                        byte[] namebytes = new byte[roomNameLen];
                        System.arraycopy(dst, 2, namebytes, 0, roomNameLen);
                        String name = null;
                        try {
                            name = new String(namebytes, "utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        room.setName(name);
                        Log.d("zw", "room name is " + name);
                    } else {
                        room.setName("Room" + (roomId + 1));
                    }
                    break;
                }
            }
        } else {
            LogUtils.i("forbidenLineData data not error");
            return new ParseResult(ParseResult.MSG_PARSE_FAIL_DATA_ERROR);
        }
        return new ParseResult(ParseResult.MSG_PARSE_SUCCESS);
    }

    private static ArrayList<Double> getPoints(byte[] bytes, TuyaLaserMap map) {
        ArrayList<Double> doubles = new ArrayList<>();
        for (int i = 0; i < bytes.length / 4; i++) {
            int pointStart = i * 4;
            byte b1 = bytes[pointStart];
            byte b2 = bytes[pointStart + 1];
            byte b3 = bytes[pointStart + 2];
            byte b4 = bytes[pointStart + 3];
            double x = StringUtils.convertTwoBytesToInt(b1, b2);
            double y = StringUtils.convertTwoBytesToInt(b3, b4);

            x = x / 10.0f;
            y = y / 10.0f;

            x = map.x_min + x;
            y = map.y_min - y;

            Log.d("liunian", "forbidenLineData x : " + x + "==== y : " + y);

            doubles.add(x);
            doubles.add(y);
        }
        return doubles;
    }

    private static void clearCleanArea(List<AreaInfo> areaInfos) {
        if (areaInfos != null) {
            for (int i = 0; i < areaInfos.size(); i++) {
                AreaInfo areaInfo = areaInfos.get(i);
                if (areaInfo.getType() == AreaInfo.TYPE_CLEAN) {
                    areaInfos.remove(i);
                    i--;
                }
            }
        }
    }

    private static void clearForbidenLines(List<AreaInfo> areaInfos) {
        if (areaInfos != null) {
            for (int i = 0; i < areaInfos.size(); i++) {
                AreaInfo areaInfo = areaInfos.get(i);
                if (areaInfo.getType() == AreaInfo.TYPE_FORBIDDEN_LINE) {
                    areaInfos.remove(areaInfo);
                    i--;
                }
            }
        }
    }

    private static void clearForbidenArea(List<AreaInfo> areaInfos) {
        if (areaInfos != null) {
            for (int i = 0; i < areaInfos.size(); i++) {
                AreaInfo areaInfo = areaInfos.get(i);
                if (areaInfo.getType() == AreaInfo.TYPE_FORBIDDEN || areaInfo.getType() == AreaInfo.TYPE_FORBIDDEN_MOP) {
                    areaInfos.remove(i);
                    i--;
                }
            }
        }
    }

    private static void transPoseAr(TuyaLaserPath path, TuyaLaserMap map) {
        path.destPathPoints.clear();
        for (int i = 0; i < path.pathPoints.size(); i++) {
//            Log.d("Path", "PosPathX1 = " + path.pathPoints.get(i) );
            PathPoint pathPoint = path.pathPoints.get(i);
            float x = pathPoint.x / 10.0f;
            float y = pathPoint.y / 10.0f;

            x = map.x_min + x;
            y = map.y_min - y;

            path.destPathPoints.add(new PathPoint(x, y, pathPoint.type));

        }
        Log.d(TAG, "path data test");
    }

    public static ArrayList<Short> getWorldPoint(PointF p1, TuyaLaserMap map) {
        ArrayList<Short> wordPoint = new ArrayList<>();
        float x = (p1.x - map.x_min) * 10;
        float y = (map.y_min - p1.y) * 10;
        wordPoint.add((short) x);
        wordPoint.add((short) y);
        Log.i(TAG, "worldpoint x: " + wordPoint.get(0) + " y: " + wordPoint.get(1));
        return wordPoint;
    }

}
